package com.maixy.studyonlineapi.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Slf4j
@Component
public class OssUtil implements InitializingBean {

    @Value("${oss.endpoint}")
    private String endpoint;

    /**
     * 阿里云AccessKeyId
     */
    @Value("${oss.accessKeyId}")
    private String accessKeyId;

    /**
     * 阿里云AccessKeySecret
     */
    @Value("${oss.accessKeySecret}")
    private String accessKeySecret;

    /**
     * oss bucket名称
     */
    @Value("${oss.bucket}")
    private String bucket;

    private OSS client;


    @Override
    public void afterPropertiesSet() throws Exception {
        // 创建OSSClient实例。
        this.client = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    }

    /**
     * 上传文件
     *
     * @param fileBytes 文件Bytes
     * @param key       文件key
     * @return 文件key
     */
    public String upload(byte[] fileBytes, String key) {
        try {
            if(StringUtils.isBlank(key)){
                return null;
            }
            if('/' == key.charAt(0)) {
                key = key.substring(1);
            }
            client.putObject(bucket, key, new ByteArrayInputStream(fileBytes));
        } catch (Exception e) {
            log.error("阿里云OSS上传文件失败", e);
        }
        return key;
    }

    /**
     * 判断文件是否存在
     * @param url 文件路径
     * @return java.lang.Boolean
     */
    public Boolean exist(String url) {
        if (StringUtils.isBlank(url)) {
            return false;
        }
        String objectName;
        if (url.contains("/")) {
            objectName = url.substring(url.indexOf("/") + 1);
        } else {
            objectName = url;
        }
        return client.doesObjectExist(bucket, objectName);
    }

    public void getOssZip(String zipName, List<String> keyList) {
        try {
            // 创建临时文件
            File zipFile = File.createTempFile("abc", ".zip");
            FileOutputStream f = new FileOutputStream(zipFile);
            //作用是为任何OutputStream产生校验和
            //第一个参数是制定产生校验和的输出流，第二个参数是指定Checksum的类型 （Adler32（较快）和CRC32两种）
            CheckedOutputStream checkedOutputStream = new CheckedOutputStream(f, new Adler32());
            // 用于将数据压缩成Zip文件格式
            ZipOutputStream zos = new ZipOutputStream(checkedOutputStream);

            for (String key : keyList) {
                // 获取Object，返回结果为OSSObject对象
                if ('/' == key.charAt(0)) {
                    key = key.substring(1);
                }
                OSSObject object = client.getObject(bucket, key);
                InputStream inputStream = object.getObjectContent();
                // 对于每一个要被存放到压缩包的文件，都必须调用ZipOutputStream对象的putNextEntry()方法，确保压缩包里面文件不同名
                zos.putNextEntry(new ZipEntry(key));
                int bytesRead;
                // 向压缩文件中输出数据
                while ((bytesRead = inputStream.read()) != -1) {
                    zos.write(bytesRead);
                }
                inputStream.close();
                // 当前文件写完，定位为写入下一条项目
                zos.closeEntry();
            }
            zos.close();
            FileInputStream fis = new FileInputStream(zipFile);
            //重新上传到OSS里
            client.putObject(bucket, zipName, fis);
            // 关闭流
            fis.close();
            // 删除临时文件
            zipFile.delete();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
